home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Source Code / Visual Basic Source Code.iso / vbsource / win9591a / appbar.cls < prev    next >
Encoding:
Visual Basic class definition  |  1999-07-06  |  67.3 KB  |  2,289 lines

  1. VERSION 1.0 CLASS
  2. BEGIN
  3.   MultiUse = -1  'True
  4.   Persistable = 0  'NotPersistable
  5.   DataBindingBehavior = 0  'vbNone
  6.   DataSourceBehavior  = 0  'vbNone
  7.   MTSTransactionMode  = 0  'NotAnMTSObject
  8. END
  9. Attribute VB_Name = "TAppBar"
  10. Attribute VB_GlobalNameSpace = False
  11. Attribute VB_Creatable = True
  12. Attribute VB_PredeclaredId = False
  13. Attribute VB_Exposed = False
  14.  
  15.  
  16. Option Explicit
  17.  
  18.  
  19. ' CONST Section ---------------------------------------------------------------
  20.  
  21.   ' Debugging Mode On/Off
  22.   #Const DEBUG_MODE = False
  23.  
  24.   ' AppBar's user notification message
  25.   Const WM_USER = &H400
  26.   Const WM_APPBARNOTIFY = WM_USER + 100
  27.   
  28.   ' We need a timer to determine when the AppBar should be re-hidden
  29.   Const AUTO_HIDE_TIMER_ID = 100
  30.   Const SLIDE_DEF_TIMER_INTERVAL = 400 ' milliseconds
  31.   
  32.   ' Registry Root Keys
  33.   Const HKEY_CURRENT_USER = &H80000001
  34.   Const HKEY_LOCAL_MACHINE = &H80000002
  35.  
  36.   ' Defaults
  37.   Const AB_DEF_SIZE_INC = 1
  38.   Const AB_DEF_DOCK_SIZE = 32
  39.   Const AB_DEF_ROOT_KEY = HKEY_CURRENT_USER
  40.   Const AB_DEF_KEY_NAME = "Software\AppBar\1.4\VB"
  41.  
  42.   ' You can send to the Windows shell one of the following messages:
  43.   ' Message             Description
  44.   ' --------------      --------------------------------------------------
  45.   ' ABM_NEW             Register a new AppBar to the system
  46.   ' ABM_REMOVE          Remove a previously created AppBar from the system
  47.   ' ABM_QUERYPOS        Query the AppBar position
  48.   ' ABM_SETPOS          Set the AppBar position
  49.   ' ABM_GETSTATE        Get the edge the Appbar is docked to
  50.   ' ABM_GETTASKBARPOS   Get the Explorer Taskbar position
  51.   ' ABM_ACTIVATE        Activate the AppBar
  52.   ' ABM_GETAUTOHIDEBAR  Query if AppBar has Auto-hide behavior
  53.   ' ABM_SETAUTOHIDEBAR  Set the AppBar's Auto-hide behavior
  54.  
  55.   ' The ABM_message constants are defined in SHELLAPI.H as follows:
  56.   Const ABM_NEW = &H0
  57.   Const ABM_REMOVE = &H1
  58.   Const ABM_QUERYPOS = &H2
  59.   Const ABM_SETPOS = &H3
  60.   Const ABM_GETSTATE = &H4
  61.   Const ABM_GETTASKBARPOS = &H5
  62.   Const ABM_ACTIVATE = &H6
  63.   Const ABM_GETAUTOHIDEBAR = &H7
  64.   Const ABM_SETAUTOHIDEBAR = &H8
  65.   Const ABM_WINDOWPOSCHANGED = &H9
  66.  
  67.   ' An AppBar can be in one of 6 states shown in the table below:
  68.   ' State          Description
  69.   ' -----------    -----------------------------------------------------
  70.   ' ABE_UNKNOWN    The Appbar is in an unknown state
  71.   '                (usually during construction/destruction)
  72.   ' ABE_FLOAT      The AppBar is floating on the screen
  73.   ' ABE_LEFT       The Appbar is docked on the left   edge of the screen
  74.   ' ABE_TOP        The Appbar is docked on the top    edge of the screen
  75.   ' ABE_RIGHT      The Appbar is docked on the right  edge of the screen
  76.   ' ABE_BOTTOM     The Appbar is docked on the bottom edge of the screen
  77.  
  78.   ' The ABE_edge state constants are defined in SHELLAPI.H as follows:
  79.   Const ABE_LEFT = 0
  80.   Const ABE_TOP = 1
  81.   Const ABE_RIGHT = 2
  82.   Const ABE_BOTTOM = 3
  83.  
  84.   ' The ABE_UNKNOWN and ABE_FLOAT constants are defined here as follows:
  85.   Const ABE_UNKNOWN = 4
  86.   Const ABE_FLOAT = 5
  87.   
  88.   ' An AppBar can have several behavior flags as shown below:
  89.   ' Flag                        Description
  90.   ' --------------------------- -----------------------------------
  91.   ' ABF_ALLOWLEFT               Allow dock on left   of screen
  92.   ' ABF_ALLOWRIGHT              Allow dock on right  of screen
  93.   ' ABF_ALLOWTOP                Allow dock on top    of screen
  94.   ' ABF_ALLOWBOTTOM             Allow dock on bottom of screen
  95.   ' ABF_ALLOWFLOAT              Allow float in the middle of screen
  96.   
  97.   ' The ABF_* constants are defined here as follows:
  98.   Const ABF_ALLOWLEFT = 1
  99.   Const ABF_ALLOWRIGHT = 2
  100.   Const ABF_ALLOWTOP = 4
  101.   Const ABF_ALLOWBOTTOM = 8
  102.   Const ABF_ALLOWFLOAT = 16
  103.  
  104.   ' The ABN_* constants are defined here as follows:
  105.   Const ABN_FULLSCREENAPP = &H2
  106.   Const ABN_POSCHANGED = &H1
  107.   Const ABN_WINDOWARRANGE = &H3
  108.  
  109.   ' DeleteMenu Selectors
  110.   Const SC_RESTORE = &HF120
  111.   Const SC_MINIMIZE = &HF020
  112.   Const SC_MAXIMIZE = &HF030
  113.   Const MF_BYCOMMAND = &H0&
  114.   
  115.   ' GetKeyState and GetAsyncKeyState Selectors
  116.   Const VK_LBUTTON = &H1
  117.   Const VK_RBUTTON = &H2
  118.   Const VK_CONTROL = &H11
  119.  
  120.   ' GetSystemMetrics Selectors
  121.   Const SM_CXSCREEN = 0
  122.   Const SM_CYSCREEN = 1
  123.   Const SM_CXVSCROLL = 2
  124.   Const SM_CYHSCROLL = 3
  125.   Const SM_CXBORDER = 5
  126.   Const SM_CYBORDER = 6
  127.   Const SM_SWAPBUTTON = 23
  128.   Const SM_CXDOUBLECLK = 36
  129.   Const SM_CYDOUBLECLK = 37
  130.  
  131.   ' MessageBox Selectors
  132.   Const MB_OK = &H0&
  133.   Const MB_ICONINFORMATION = &H40&
  134.   
  135.   ' ModifyStyle Selectors
  136.   Const GWL_STYLE = (-16)
  137.   Const GWL_EXSTYLE = (-20)
  138.   Const WS_CAPTION = &HC00000
  139.   Const WS_SYSMENU = &H80000
  140.   Const WS_EX_APPWINDOW = &H40000
  141.   
  142.   ' Registry Selectors
  143.   Const REG_OPTION_NON_VOLATILE = 0
  144.   Const REG_BINARY = 3
  145.   Const STANDARD_RIGHTS_ALL = &H1F0000
  146.   Const SYNCHRONIZE = &H100000
  147.   Const KEY_QUERY_VALUE = &H1
  148.   Const KEY_SET_VALUE = &H2
  149.   Const KEY_CREATE_SUB_KEY = &H4
  150.   Const KEY_ENUMERATE_SUB_KEYS = &H8
  151.   Const KEY_NOTIFY = &H10
  152.   Const KEY_CREATE_LINK = &H20
  153.   Const KEY_ALL_ACCESS = ((STANDARD_RIGHTS_ALL Or _
  154.                            KEY_QUERY_VALUE Or _
  155.                            KEY_SET_VALUE Or _
  156.                            KEY_CREATE_SUB_KEY Or _
  157.                            KEY_ENUMERATE_SUB_KEYS Or _
  158.                            KEY_NOTIFY Or _
  159.                            KEY_CREATE_LINK) And (Not SYNCHRONIZE))
  160.   
  161.   ' SetWindowPos Selectors
  162.   Const SWP_NOSIZE = &H1
  163.   Const SWP_NOMOVE = &H2
  164.   Const SWP_NOZORDER = &H4
  165.   Const SWP_NOACTIVATE = &H10
  166.   Const SWP_DRAWFRAME = &H20
  167.   
  168.   Const HWND_NOTOPMOST = -2
  169.   Const HWND_TOPMOST = -1
  170.   Const HWND_BOTTOM = 1
  171.  
  172.   ' ShowWindow Selectors
  173.   Const SW_HIDE = 0
  174.   Const SW_SHOW = 5
  175.   
  176.   ' SystemParametersInfo Selectors
  177.   Const SPI_GETDRAGFULLWINDOWS = 38
  178.   Const SPI_GETWORKAREA = 48
  179.  
  180.   ' WM_ACTIVATE Selectors
  181.   Const WA_INACTIVE = 0
  182.  
  183.   ' WM_NCHITTEST Selectors
  184.   Const HTCLIENT = 1
  185.   Const HTCAPTION = 2
  186.   Const HTLEFT = 10
  187.   Const HTRIGHT = 11
  188.   Const HTTOP = 12
  189.   Const HTTOPLEFT = 13
  190.   Const HTTOPRIGHT = 14
  191.   Const HTBOTTOM = 15
  192.   Const HTBOTTOMLEFT = 16
  193.   Const HTBOTTOMRIGHT = 17
  194.   Const HTBORDER = 18
  195.   Const HTSIZEFIRST = HTLEFT
  196.   Const HTSIZELAST = HTBOTTOMRIGHT
  197.   
  198.   ' WM_SIZING Selectors
  199.   Const WMSZ_LEFT = 1
  200.   Const WMSZ_RIGHT = 2
  201.   Const WMSZ_TOP = 3
  202.   Const WMSZ_TOPLEFT = 4
  203.   Const WMSZ_TOPRIGHT = 5
  204.   Const WMSZ_BOTTOM = 6
  205.   Const WMSZ_BOTTOMLEFT = 7
  206.   Const WMSZ_BOTTOMRIGHT = 8
  207.  
  208.  
  209. ' TYPE Section ----------------------------------------------------------------
  210.  
  211.   ' The following enumerated type defines the constants in the ABM_* table
  212.   Enum TAppBarMessage
  213.     abmNew = ABM_NEW
  214.     abmRemove = ABM_REMOVE
  215.     abmQueryPos = ABM_QUERYPOS
  216.     abmSetPos = ABM_SETPOS
  217.     abmGetState = ABM_GETSTATE
  218.     abmGetTaskBarPos = ABM_GETTASKBARPOS
  219.     abmActivate = ABM_ACTIVATE
  220.     abmGetAutoHideBar = ABM_GETAUTOHIDEBAR
  221.     abmSetAutoHideBar = ABM_SETAUTOHIDEBAR
  222.     abmWindowPosChanged = ABM_WINDOWPOSCHANGED
  223.   End Enum
  224.  
  225.   ' The following enumerated type defines the constants in the ABE_* table
  226.   ' (Values are mutually exclusive)
  227.   Enum TAppBarEdge
  228.     abeLeft = ABE_LEFT
  229.     abeTop = ABE_TOP
  230.     abeRight = ABE_RIGHT
  231.     abeBottom = ABE_BOTTOM
  232.     abeUnknown = ABE_UNKNOWN
  233.     abeFloat = ABE_FLOAT
  234.   End Enum
  235.  
  236.   ' The following enumerated type defines the constants in the ABF_* table
  237.   ' (Values can be OR'ed)
  238.   Enum TAppBarFlags
  239.     abfAllowLeft = ABF_ALLOWLEFT
  240.     abfAllowTop = ABF_ALLOWTOP
  241.     abfAllowRight = ABF_ALLOWRIGHT
  242.     abfAllowBottom = ABF_ALLOWBOTTOM
  243.     abfAllowFloat = ABF_ALLOWFLOAT
  244.   End Enum
  245.   
  246.   ' The following enumerated type defines the AppBar behavior in the Taskbar
  247.   Enum TAppBarTaskEntry
  248.     abtShow
  249.     abtHide
  250.     abtFloatDependent
  251.   End Enum
  252.  
  253.   ' Rectangle
  254.   Private Type Rect
  255.     Left As Long
  256.     Top As Long
  257.     Right As Long
  258.     Bottom As Long
  259.   End Type
  260.   
  261.   ' Size
  262.   Private Type Size
  263.     cx As Long
  264.     cy As Long
  265.   End Type
  266.  
  267.   ' The record below contains all of the AppBar settings that
  268.   ' can be saved/loaded in/from the Registry
  269.   Private Type TAppBarSettings
  270.     cbSize         As Long         ' Size of this structure
  271.     abEdge         As TAppBarEdge  ' ABE_UNKNOWN, ABE_FLOAT, or ABE_edge
  272.     abFlags        As TAppBarFlags ' ABF_* flags
  273.     bAutoHide      As Boolean      ' Should AppBar be auto-hidden when docked?
  274.     bAlwaysOnTop   As Boolean      ' Should AppBar always be on top?
  275.     bSlideEffect   As Boolean      ' Should AppBar slide?
  276.     nTimerInterval As Long         ' Slide Timer Interval (determines speed)
  277.     szSizeInc      As Size         ' Discrete width/height size increments
  278.     szDockSize     As Size         ' Width/Height for docked bar
  279.     rcFloat        As Rect         ' Floating rectangle in screen coordinates
  280.     nMinWidth      As Long         ' Min allowed width
  281.     nMinHeight     As Long         ' Min allowed height
  282.     nMaxWidth      As Long         ' Max allowed width
  283.     nMaxHeight     As Long         ' Max allowed height
  284.     szMinDockSize  As Size         ' Min Width/Height when docked
  285.     szMaxDockSize  As Size         ' Max Width/Height when docked
  286.     abTaskEntry    As TAppBarTaskEntry ' AppBar behavior in the Taskbar
  287.   End Type
  288.  
  289.   ' The record below contains the settings location in the registry
  290.   Private Type TAppBarSettingsLocation
  291.     nRootKey As Long   ' HKEY_CURRENT_USER or HKEY_LOCAL_MACHINE
  292.     KeyName  As String ' Key Name starting from root
  293.   End Type
  294.   
  295.   ' Point
  296.   Private Type POINTAPI
  297.     x As Long
  298.     y As Long
  299.   End Type
  300.  
  301.   ' SmallPoint
  302.   Private Type POINTS
  303.     x  As Integer
  304.     y  As Integer
  305.   End Type
  306.   
  307.   ' MinMaxInfo
  308.   Private Type MINMAXINFO
  309.     ptReserved As POINTAPI
  310.     ptMaxSize As POINTAPI
  311.     ptMaxPosition As POINTAPI
  312.     ptMinTrackSize As POINTAPI
  313.     ptMaxTrackSize As POINTAPI
  314.   End Type
  315.  
  316.   ' CreateStruct
  317.   Private Type CREATESTRUCT
  318.     lpCreateParams As Long
  319.     hInstance As Long
  320.     hMenu As Long
  321.     hWndParent As Long
  322.     cy As Long
  323.     cx As Long
  324.     y As Long
  325.     x As Long
  326.     style As Long
  327.     lpszName As String
  328.     lpszClass As String
  329.     ExStyle As Long
  330.   End Type
  331.  
  332.   ' AppBarData
  333.   Private Type APPBARDATA
  334.     cbSize As Long
  335.     hwnd As Long
  336.     uCallbackMessage As Long
  337.     uEdge As Long
  338.     rc As Rect
  339.     lParam As Long
  340.   End Type
  341.  
  342.  
  343. ' DECL Section ----------------------------------------------------------------
  344.  
  345. ' ClientToScreen
  346. Private Declare Function ClientToScreen _
  347.                 Lib "user32" _
  348.                 (ByVal hwnd As Long, _
  349.                  ByRef lpPoint As POINTAPI) As Long
  350.                  
  351. ' CopyMemory
  352. Private Declare Function CopyMemory _
  353.                 Lib "kernel32" _
  354.                 Alias "RtlMoveMemory" _
  355.                 (ByVal pDest As Any, _
  356.                  ByVal pSource As Any, _
  357.                  ByVal ByteLen As Long) As Long
  358.  
  359. ' DeleteMenu
  360. Private Declare Function DeleteMenu _
  361.                 Lib "user32" _
  362.                 (ByVal hMenu As Long, _
  363.                  ByVal nPosition As Long, _
  364.                  ByVal wFlags As Long) As Long
  365.  
  366. ' GetActiveWindow
  367. Private Declare Function GetActiveWindow _
  368.                 Lib "user32" () As Long
  369.  
  370. ' GetAsyncKeyState
  371. Private Declare Function GetAsyncKeyState _
  372.                 Lib "user32" _
  373.                 (ByVal vKey As Long) As Integer
  374.                 
  375. ' GetClientRect
  376. Private Declare Function GetClientRect _
  377.                 Lib "user32" _
  378.                 (ByVal hwnd As Long, _
  379.                  ByRef lpRect As Rect) As Long
  380.  
  381. ' GetKeyState
  382. Private Declare Function GetKeyState _
  383.                 Lib "user32" _
  384.                 (ByVal nVirtKey As Long) As Integer
  385.  
  386. ' GetMessagePos
  387. Private Declare Function GetMessagePos _
  388.                 Lib "user32" () As Long
  389.  
  390. ' GetSystemMenu
  391. Private Declare Function GetSystemMenu _
  392.                 Lib "user32" _
  393.                 (ByVal hwnd As Long, _
  394.                  ByVal bRevert As Long) As Long
  395.  
  396. ' GetSystemMetrics
  397. Private Declare Function GetSystemMetrics _
  398.                 Lib "user32" _
  399.                 (ByVal nIndex As Long) As Long
  400.  
  401. ' GetTickCount
  402. Private Declare Function GetTickCount _
  403.                 Lib "kernel32" () As Long
  404.  
  405. ' GetWindowLong
  406. Private Declare Function GetWindowLong _
  407.                 Lib "user32" Alias "GetWindowLongA" _
  408.                 (ByVal hwnd As Long, _
  409.                  ByVal nIndex As Long) As Long
  410.  
  411. ' GetWindowRect
  412. Private Declare Function GetWindowRect _
  413.                 Lib "user32" _
  414.                 (ByVal hwnd As Long, _
  415.                  ByRef lpRect As Rect) As Long
  416.  
  417. ' InflateRect
  418. Private Declare Function InflateRect _
  419.                 Lib "user32" _
  420.                 (ByRef lpRect As Rect, _
  421.                  ByVal x As Long, _
  422.                  ByVal y As Long) As Long
  423.  
  424. ' KillTimer
  425. Private Declare Function KillTimer _
  426.                 Lib "user32" _
  427.                 (ByVal hwnd As Long, _
  428.                  ByVal nIDEvent As Long) As Long
  429.  
  430. ' MessageBox
  431. Private Declare Function MessageBox _
  432.                 Lib "user32" _
  433.                 Alias "MessageBoxA" _
  434.                 (ByVal hwnd As Long, _
  435.                  ByVal lpText As String, _
  436.                  ByVal lpCaption As String, _
  437.                  ByVal wType As Long) As Long
  438.  
  439. ' RegCloseKey
  440. Private Declare Function RegCloseKey _
  441.                 Lib "advapi32.dll" _
  442.                 (ByVal hKey As Long) As Long
  443.  
  444. ' RegCreateKeyEx
  445. Private Declare Function RegCreateKeyEx _
  446.                 Lib "advapi32.dll" _
  447.                 Alias "RegCreateKeyExA" _
  448.                 (ByVal hKey As Long, _
  449.                  ByVal lpSubKey As String, _
  450.                  ByVal Reserved As Long, _
  451.                  ByVal lpClass As String, _
  452.                  ByVal dwOptions As Long, _
  453.                  ByVal samDesired As Long, _
  454.                  ByVal lpSecurityAttributes As Long, _
  455.                  ByRef phkResult As Long, _
  456.                  ByRef lpdwDisposition As Long) As Long
  457.  
  458. ' RegOpenKeyEx
  459. Private Declare Function RegOpenKeyEx _
  460.                 Lib "advapi32.dll" _
  461.                 Alias "RegOpenKeyExA" _
  462.                 (ByVal hKey As Long, _
  463.                  ByVal lpSubKey As String, _
  464.                  ByVal ulOptions As Long, _
  465.                  ByVal samDesired As Long, _
  466.                  ByRef phkResult As Long) As Long
  467.  
  468. ' RegQueryValueEx
  469. Private Declare Function RegQueryValueEx _
  470.                 Lib "advapi32.dll" _
  471.                 Alias "RegQueryValueExA" _
  472.                 (ByVal hKey As Long, _
  473.                  ByVal lpValueName As String, _
  474.                  ByVal lpReserved As Long, _
  475.                  ByRef lpType As Long, _
  476.                  ByRef lpData As Any, _
  477.                  ByRef lpcbData As Long) As Long
  478.                  
  479. ' RegSetValueEx
  480. Private Declare Function RegSetValueEx _
  481.                 Lib "advapi32.dll" _
  482.                 Alias "RegSetValueExA" _
  483.                 (ByVal hKey As Long, _
  484.                  ByVal lpValueName As String, _
  485.                  ByVal Reserved As Long, _
  486.                  ByVal dwType As Long, _
  487.                  ByRef lpData As Any, _
  488.                  ByVal cbData As Long) As Long
  489.                  
  490. ' ScreenToClient
  491. Private Declare Function ScreenToClient _
  492.                 Lib "user32" _
  493.                 (ByVal hwnd As Long, _
  494.                  ByRef lpPoint As POINTAPI) As Long
  495.  
  496. ' SetTimer
  497. Private Declare Function SetTimer _
  498.                 Lib "user32" _
  499.                 (ByVal hwnd As Long, _
  500.                  ByVal nIDEvent As Long, _
  501.                  ByVal uElapse As Long, _
  502.                  ByVal lpTimerFunc As Long) As Long
  503.  
  504. ' SetWindowLong
  505. Private Declare Function SetWindowLong _
  506.                 Lib "user32" Alias "SetWindowLongA" _
  507.                 (ByVal hwnd As Long, _
  508.                  ByVal nIndex As Long, _
  509.                  ByVal dwNewLong As Long) As Long
  510.  
  511. ' SetWindowPos
  512. Private Declare Function SetWindowPos _
  513.                 Lib "user32" _
  514.                 (ByVal hwnd As Long, _
  515.                  ByVal hWndInsertAfter As Long, _
  516.                  ByVal x As Long, _
  517.                  ByVal y As Long, _
  518.                  ByVal cx As Long, _
  519.                  ByVal cy As Long, _
  520.                  ByVal wFlags As Long) As Long
  521.  
  522. ' SHAppBarMessage
  523. Private Declare Function SHAppBarMessage _
  524.                 Lib "shell32.dll" _
  525.                 (ByVal dwMessage As Long, pData As APPBARDATA) As Long
  526.  
  527. ' ShowWindow
  528. Private Declare Function ShowWindow _
  529.                 Lib "user32" _
  530.                 (ByVal hwnd As Long, _
  531.                  ByVal nCmdShow As Long) As Long
  532.  
  533. ' SystemParametersInfo
  534. Private Declare Function SystemParametersInfo _
  535.                 Lib "user32" _
  536.                 Alias "SystemParametersInfoA" _
  537.                 (ByVal uAction As Long, _
  538.                  ByVal uParam As Long, _
  539.                  ByVal lpvParam As Any, _
  540.                  ByVal fuWinIni As Long) As Long
  541.  
  542. ' UpdateWindow
  543. Private Declare Function UpdateWindow _
  544.                 Lib "user32" _
  545.                 (ByVal hwnd As Long) As Long
  546.  
  547.  
  548. ' CLASS DATA MEMBERS Section --------------------------------------------------
  549.  
  550.  
  551. ' PRIVATE
  552.   
  553.   ' Internal implementation state variables
  554.   
  555.     ' The AppBar Form
  556.     Private Self As Form
  557.     
  558.     ' This AppBar's settings info
  559.     Private FABS As TAppBarSettings
  560.  
  561.     ' We need a member variable which tracks the proposed edge of the
  562.     ' AppBar while the user is moving it, deciding where to position it.
  563.     ' While not moving, this member must contain ABE_UNKNOWN so that
  564.     ' GetEdge returns the current edge contained in FABS.abEdge.
  565.     ' While moving the AppBar, FabEdgeProposedPrev contains the
  566.     ' proposed edge based on the position of the AppBar.  The proposed
  567.     ' edge becomes the new edge when the user stops moving the AppBar.
  568.     Private FabEdgeProposedPrev As TAppBarEdge
  569.  
  570.     ' We need a member variable which tracks whether a full screen
  571.     ' application window is open
  572.     Private FbFullScreenAppOpen As Boolean
  573.  
  574.     ' We need a member variable which tracks whether our autohide window
  575.     ' is visible or not
  576.     Private FbAutoHideIsVisible As Boolean
  577.     
  578.     ' We need a member variable to store the settings location in the registry
  579.     Private FabSettingsLocation As TAppBarSettingsLocation
  580.  
  581.  
  582. ' CLASS METHODS Section -------------------------------------------------------
  583.  
  584.  
  585. ' PRIVATE
  586.  
  587.  
  588. ' Class Initialization and Termination
  589.  
  590. ' Constructs an AppBar
  591. Private Sub Class_Initialize()
  592.   
  593.   ' Force the shell to update its list of AppBars and the workarea.
  594.   ' This is a precaution and is very useful when debugging.  If you create
  595.   ' an AppBar and then just terminate the application, the shell still
  596.   ' thinks that the AppBar exists and the user's workarea is smaller than
  597.   ' it should be.  When a new AppBar is created, calling this function
  598.   ' fixes the user's workarea.
  599.   ResetSystemKnowledge
  600.  
  601.   ' Set default state of AppBar to float with no width & height
  602.   FABS.cbSize = Len(FABS)
  603.   FABS.abEdge = abeFloat
  604.   FABS.abFlags = abfAllowLeft Or _
  605.                  abfAllowTop Or _
  606.                  abfAllowRight Or _
  607.                  abfAllowBottom Or _
  608.                  abfAllowFloat
  609.   FABS.bAutoHide = False
  610.   FABS.bAlwaysOnTop = True
  611.   FABS.bSlideEffect = True
  612.   FABS.nTimerInterval = SLIDE_DEF_TIMER_INTERVAL
  613.   FABS.szSizeInc.cx = AB_DEF_SIZE_INC
  614.   FABS.szSizeInc.cy = AB_DEF_SIZE_INC
  615.   FABS.szDockSize.cx = AB_DEF_DOCK_SIZE
  616.   FABS.szDockSize.cy = AB_DEF_DOCK_SIZE
  617.   FABS.rcFloat.Left = 0
  618.   FABS.rcFloat.Top = 0
  619.   FABS.rcFloat.Right = 0
  620.   FABS.rcFloat.Bottom = 0
  621.   FABS.nMinWidth = 0
  622.   FABS.nMinHeight = 0
  623.   FABS.nMaxWidth = GetSystemMetrics(SM_CXSCREEN)
  624.   FABS.nMaxHeight = GetSystemMetrics(SM_CYSCREEN)
  625.   FABS.szMinDockSize.cx = 0
  626.   FABS.szMinDockSize.cy = 0
  627.   FABS.szMaxDockSize.cx = GetSystemMetrics(SM_CXSCREEN) \ 2
  628.   FABS.szMaxDockSize.cy = GetSystemMetrics(SM_CYSCREEN) \ 2
  629.   FABS.abTaskEntry = abtFloatDependent
  630.   FabEdgeProposedPrev = abeUnknown
  631.   FbFullScreenAppOpen = False
  632.   FbAutoHideIsVisible = False
  633.   
  634.   ' Set default location of the settings in the registry
  635.   With FabSettingsLocation
  636.     RootKey = AB_DEF_ROOT_KEY
  637.     KeyName = AB_DEF_KEY_NAME
  638.   End With
  639.  
  640. End Sub
  641.  
  642. ' Destroys a previously created AppBar
  643. Private Sub Class_Terminate()
  644.   
  645.   ResetSystemKnowledge
  646.  
  647. End Sub
  648.  
  649.  
  650. ' Internal implementation functions
  651.  
  652. ' AppBarMessage(1,2,3,4) encapsulate the shell's SHAppBarMessage function
  653. Private Function AppBarMessage(ByVal abMessage As TAppBarMessage, _
  654.                                ByVal abEdge As TAppBarEdge, _
  655.                                ByVal lParam As Long, _
  656.                                ByVal bRect As Boolean, _
  657.                                ByRef rc As Rect) As Long
  658.   Dim abd As APPBARDATA
  659.   
  660.   ' Initialize an APPBARDATA structure
  661.   abd.cbSize = Len(abd)
  662.   abd.hwnd = Self.hwnd
  663.   abd.uCallbackMessage = WM_APPBARNOTIFY
  664.   abd.uEdge = abEdge
  665.   If bRect Then
  666.     abd.rc = rc
  667.   Else
  668.     abd.rc.Left = 0
  669.     abd.rc.Top = 0
  670.     abd.rc.Right = 0
  671.     abd.rc.Bottom = 0
  672.   End If
  673.   abd.lParam = lParam
  674.   AppBarMessage = SHAppBarMessage(abMessage, abd)
  675.  
  676.   ' If the caller passed a rectangle, return the updated rectangle
  677.   If bRect Then
  678.     rc = abd.rc
  679.   End If
  680.  
  681. End Function
  682.  
  683. Private Function AppBarMessage1(ByVal abMessage As TAppBarMessage) As Long
  684.   
  685.   Dim rc As Rect
  686.   AppBarMessage1 = AppBarMessage(abMessage, abeFloat, 0, False, rc)
  687.  
  688. End Function
  689.  
  690. Private Function AppBarMessage2(ByVal abMessage As TAppBarMessage, _
  691.                                 ByVal abEdge As TAppBarEdge) As Long
  692.   Dim rc As Rect
  693.   AppBarMessage2 = AppBarMessage(abMessage, abEdge, 0, False, rc)
  694.  
  695. End Function
  696.  
  697. Private Function AppBarMessage3(ByVal abMessage As TAppBarMessage, _
  698.                                 ByVal abEdge As TAppBarEdge, _
  699.                                 ByVal lParam As Long) As Long
  700.   Dim rc As Rect
  701.   AppBarMessage3 = AppBarMessage(abMessage, abEdge, lParam, False, rc)
  702.  
  703. End Function
  704.  
  705. Private Function AppBarMessage4(ByVal abMessage As TAppBarMessage, _
  706.                                 ByVal abEdge As TAppBarEdge, _
  707.                                 ByVal lParam As Long, _
  708.                                 ByRef rc As Rect) As Long
  709.   
  710.   AppBarMessage4 = AppBarMessage(abMessage, abEdge, lParam, True, rc)
  711.  
  712. End Function
  713.  
  714. ' Gets a edge (ABE_FLOAT or ABE_edge) from a point (screen coordinates)
  715. Private Function CalcProposedState(ByRef pt As POINTS) As TAppBarEdge
  716.   
  717.   Dim bForceFloat As Boolean
  718.   
  719.   ' Force the AppBar to float if the user is holding down the Ctrl key
  720.   ' and the AppBar's style allows floating
  721.   bForceFloat = CBool(GetKeyState(VK_CONTROL) And &H8000) And _
  722.                 CBool(abfAllowFloat And FABS.abFlags)
  723.   If bForceFloat Then
  724.     CalcProposedState = abeFloat
  725.   Else
  726.     CalcProposedState = GetEdgeFromPoint(FABS.abFlags, pt)
  727.   End If
  728.  
  729. End Function
  730.  
  731. ' Gets a retangle position (screen coordinates) from a proposed state
  732. Private Function GetRect(ByVal abEdgeProposed As TAppBarEdge, _
  733.                          ByRef rcProposed As Rect)
  734.   
  735.   ' This function finds the x, y, cx, cy of the AppBar window
  736.   If abEdgeProposed = abeFloat Then
  737.     ' The AppBar is floating, the proposed rectangle is correct
  738.   Else
  739.     ' The AppBar is docked or auto-hide
  740.     ' Set dimensions to full screen
  741.     With rcProposed
  742.       .Left = 0
  743.       .Top = 0
  744.       .Right = GetSystemMetrics(SM_CXSCREEN)
  745.       .Bottom = GetSystemMetrics(SM_CYSCREEN)
  746.     End With
  747.  
  748.     ' Subtract off what we want from the full screen dimensions
  749.     If Not AutoHide Then
  750.       ' Ask the shell where we can dock
  751.       AppBarMessage4 abmQueryPos, abEdgeProposed, False, rcProposed
  752.     End If
  753.  
  754.     Select Case abEdgeProposed
  755.       Case abeLeft
  756.         rcProposed.Right = rcProposed.Left + FABS.szDockSize.cx
  757.       Case abeTop
  758.         rcProposed.Bottom = rcProposed.Top + FABS.szDockSize.cy
  759.       Case abeRight
  760.         rcProposed.Left = rcProposed.Right - FABS.szDockSize.cx
  761.       Case abeBottom
  762.         rcProposed.Top = rcProposed.Bottom - FABS.szDockSize.cy
  763.     End Select
  764.  
  765.   End If
  766.  
  767. End Function
  768.                           
  769. ' Adjusts the AppBar's location to account for autohide
  770. ' Returns TRUE if rectangle was adjusted
  771. Private Function AdjustLocationForAutohide(ByVal bShow As Boolean, _
  772.                                            ByRef rc As Rect) As Boolean
  773.   
  774.   Dim x As Long
  775.   Dim y As Long
  776.   Dim cxVisibleBorder As Long
  777.   Dim cyVisibleBorder As Long
  778.   
  779.   If (Edge = abeUnknown) Or (Edge = abeFloat) Or (Not AutoHide) Then
  780.     ' If we are not docked on an edge OR we are not auto-hidden, there is
  781.     ' nothing for us to do; just return
  782.     AdjustLocationForAutohide = False
  783.     Exit Function
  784.   End If
  785.  
  786.   ' Showing/hiding doesn't change our size; only our position
  787.   x = 0
  788.   y = 0 ' Assume a position of (0, 0)
  789.  
  790.   If bShow Then
  791.     ' If we are on the right or bottom, calculate our visible position
  792.     Select Case Edge
  793.       Case abeRight
  794.         x = GetSystemMetrics(SM_CXSCREEN) - (rc.Right - rc.Left)
  795.       Case abeBottom
  796.         y = GetSystemMetrics(SM_CYSCREEN) - (rc.Bottom - rc.Top)
  797.     End Select
  798.   Else
  799.     ' Keep a part of the AppBar visible at all times
  800.     cxVisibleBorder = 2 * GetSystemMetrics(SM_CXBORDER)
  801.     cyVisibleBorder = 2 * GetSystemMetrics(SM_CYBORDER)
  802.  
  803.     ' Calculate our x or y coordinate so that only the border is visible
  804.     Select Case Edge
  805.       Case abeLeft
  806.         x = -((rc.Right - rc.Left) - cxVisibleBorder)
  807.       Case abeRight
  808.         x = GetSystemMetrics(SM_CXSCREEN) - cxVisibleBorder
  809.       Case abeTop
  810.         y = -((rc.Bottom - rc.Top) - cyVisibleBorder)
  811.       Case abeBottom
  812.         y = GetSystemMetrics(SM_CYSCREEN) - cyVisibleBorder
  813.     End Select
  814.   End If
  815.  
  816.   With rc
  817.     .Right = x + (.Right - .Left)
  818.     .Bottom = y + (.Bottom - .Top)
  819.     .Left = x
  820.     .Top = y
  821.   End With
  822.  
  823.   AdjustLocationForAutohide = True
  824.  
  825. End Function
  826.  
  827. ' If AppBar is Autohide and docked, shows/hides the AppBar
  828. Private Function ShowHiddenAppBar(ByVal bShow As Boolean)
  829.   
  830.   Dim rc As Rect
  831.   
  832.   ' Get our window location in screen coordinates
  833.   GetWindowRect Self.hwnd, rc
  834.  
  835.   ' Assume  that we are visible
  836.   FbAutoHideIsVisible = True
  837.  
  838.   If AdjustLocationForAutohide(bShow, rc) Then
  839.     ' The rectangle was adjusted, we are an autohide bar
  840.     ' Remember whether we are visible or not
  841.     FbAutoHideIsVisible = bShow
  842.  
  843.     ' Slide window in from or out to the edge
  844.     SlideWindow rc
  845.   End If
  846.  
  847. End Function
  848.  
  849. ' When Autohide AppBar is shown/hidden, slides in/out of view
  850. Private Function SlideWindow(ByRef rcEnd As Rect)
  851.  
  852.   Dim bFullDragOn As Long
  853.   Dim rcStart As Rect
  854.   Dim dwTimeStart As Long
  855.   Dim dwTimeEnd As Long
  856.   Dim dwTime As Long
  857.   Dim x As Long
  858.   Dim y As Long
  859.   Dim w As Long
  860.   Dim h As Long
  861.   
  862.   ' Only slide the window if the user has FullDrag turned on
  863.   SystemParametersInfo SPI_GETDRAGFULLWINDOWS, 0, VarPtr(bFullDragOn), 0
  864.  
  865.   ' Get the current window position
  866.   GetWindowRect Self.hwnd, rcStart
  867.   If (FABS.bSlideEffect And bFullDragOn And _
  868.       ((rcStart.Left <> rcEnd.Left) Or _
  869.        (rcStart.Top <> rcEnd.Top) Or _
  870.        (rcStart.Right <> rcEnd.Right) Or _
  871.        (rcStart.Bottom <> rcEnd.Bottom))) Then
  872.  
  873.     ' Get our starting and ending time
  874.     dwTimeStart = GetTickCount()
  875.     dwTimeEnd = dwTimeStart + FABS.nTimerInterval
  876.     dwTime = dwTimeStart
  877.     While (dwTime < dwTimeEnd)
  878.       ' While we are still sliding, calculate our new position
  879.       x = rcStart.Left - (rcStart.Left - rcEnd.Left) _
  880.           * (dwTime - dwTimeStart) \ FABS.nTimerInterval
  881.  
  882.       y = rcStart.Top - (rcStart.Top - rcEnd.Top) _
  883.           * (dwTime - dwTimeStart) \ FABS.nTimerInterval
  884.  
  885.       w = (rcStart.Right - rcStart.Left) _
  886.           - ((rcStart.Right - rcStart.Left) - (rcEnd.Right - rcEnd.Left)) _
  887.           * (dwTime - dwTimeStart) \ FABS.nTimerInterval
  888.  
  889.       h = (rcStart.Bottom - rcStart.Top) _
  890.           - ((rcStart.Bottom - rcStart.Top) - (rcEnd.Bottom - rcEnd.Top)) _
  891.           * (dwTime - dwTimeStart) \ FABS.nTimerInterval
  892.  
  893.       ' Show the window at its changed position
  894.       SetWindowPos Self.hwnd, 0, x, y, w, h, _
  895.                    SWP_NOZORDER Or SWP_NOACTIVATE Or SWP_DRAWFRAME
  896.       UpdateWindow Self.hwnd
  897.       dwTime = GetTickCount()
  898.     Wend
  899.   End If
  900.  
  901.   ' Make sure that the window is at its final position
  902.   With Self
  903.     .Left = rcEnd.Left * Screen.TwipsPerPixelX
  904.     .Top = rcEnd.Top * Screen.TwipsPerPixelY
  905.     .Width = (rcEnd.Right - rcEnd.Left) * Screen.TwipsPerPixelX
  906.     .Height = (rcEnd.Bottom - rcEnd.Top) * Screen.TwipsPerPixelY
  907.   End With
  908.  
  909. End Function
  910.  
  911. ' Returns which edge we're autohidden on or ABE_UNKNOWN
  912. Private Function GetAutohideEdge() As TAppBarEdge
  913.   
  914.   If Self.hwnd = AppBarMessage2(abmGetAutoHideBar, abeLeft) Then
  915.     GetAutohideEdge = abeLeft
  916.   ElseIf Self.hwnd = AppBarMessage2(abmGetAutoHideBar, abeTop) Then
  917.     GetAutohideEdge = abeTop
  918.   ElseIf Self.hwnd = AppBarMessage2(abmGetAutoHideBar, abeRight) Then
  919.     GetAutohideEdge = abeRight
  920.   ElseIf Self.hwnd = AppBarMessage2(abmGetAutoHideBar, abeBottom) Then
  921.     GetAutohideEdge = abeBottom
  922.   Else
  923.     ' NOTE: If AppBar is docked but not auto-hidden, we return ABE_UNKNOWN
  924.     GetAutohideEdge = abeUnknown
  925.   End If
  926.  
  927. End Function
  928.  
  929. ' Returns a TSmallPoint that gives the cursor position in screen coords
  930. Private Function GetMessagePosition() As POINTS
  931.   
  932.   Dim pt As POINTS
  933.   Dim dw As Long
  934.   
  935.   dw = GetMessagePos()
  936.   pt.x = CInt(dw And &H7FFF)
  937.   pt.y = CInt((dw And &H7FFF0000) \ &H10000)
  938.   GetMessagePosition = pt
  939.  
  940. End Function
  941.  
  942. ' Changes the style of a window (translated from AfxModifyStyle)
  943. Private Function ModifyStyle(ByVal hwnd As Long, _
  944.                              ByVal nStyleOffset As Long, _
  945.                              ByVal dwRemove As Long, _
  946.                              ByVal dwAdd As Long, _
  947.                              ByVal nFlags As Long, _
  948.                              ByVal bRefresh As Boolean) As Boolean
  949.   
  950.   Dim dwStyle As Long
  951.   Dim dwNewStyle As Long
  952.   
  953.   dwStyle = GetWindowLong(hwnd, nStyleOffset)
  954.   dwNewStyle = (dwStyle And (Not dwRemove)) Or dwAdd
  955.  
  956.   If dwStyle = dwNewStyle Then
  957.     ModifyStyle = False
  958.     Exit Function
  959.   End If
  960.  
  961.   If bRefresh Then
  962.     ShowWindow hwnd, SW_HIDE
  963.   End If
  964.   
  965.   SetWindowLong hwnd, nStyleOffset, dwNewStyle
  966.  
  967.   If bRefresh Then
  968.     ShowWindow hwnd, SW_SHOW
  969.   End If
  970.   
  971.   If nFlags <> 0 Then
  972.     SetWindowPos hwnd, 0, 0, 0, 0, 0, _
  973.       SWP_NOSIZE Or SWP_NOMOVE Or SWP_NOZORDER Or SWP_NOACTIVATE Or nFlags
  974.   End If
  975.   
  976.   ModifyStyle = True
  977.  
  978. End Function
  979.  
  980. Private Function PtInRect(ByRef rc As Rect, ByRef pt As POINTS) As Boolean
  981.   
  982.   PtInRect = (pt.x >= rc.Left) And (pt.x <= rc.Right) And _
  983.              (pt.y >= rc.Top) And (pt.y <= rc.Bottom)
  984.  
  985. End Function
  986.  
  987. Private Function ControlAtPos(ByRef Pos As POINTAPI, _
  988.                               ByVal AllowDisabled As Boolean) As Boolean
  989.   Dim Control As Control
  990.   Dim pt As POINTS
  991.   Dim rc As Rect
  992.   
  993.   
  994.   
  995. End Function
  996.  
  997.  
  998. ' FRIEND
  999.  
  1000.  
  1001. ' Property selector functions
  1002.  
  1003. ' Property Flags : Allowed dockable edges
  1004. ' Get
  1005. Friend Property Get Flags() As TAppBarFlags
  1006.   Flags = FABS.abFlags
  1007. End Property
  1008.  
  1009. ' Let
  1010. Friend Property Let Flags(ByVal abFlags As TAppBarFlags)
  1011.   FABS.abFlags = abFlags
  1012. End Property
  1013.  
  1014. ' Property HorzSizeInc : Horizontal size increment
  1015. ' Get
  1016. Friend Property Get HorzSizeInc() As Long
  1017.   HorzSizeInc = FABS.szSizeInc.cx
  1018. End Property
  1019.  
  1020. ' Let
  1021. Friend Property Let HorzSizeInc(ByVal nIncrement As Long)
  1022.   FABS.szSizeInc.cx = nIncrement
  1023. End Property
  1024.  
  1025. ' Property VertSizeInc : Vertical size increment
  1026. ' Get
  1027. Friend Property Get VertSizeInc() As Long
  1028.   VertSizeInc = FABS.szSizeInc.cy
  1029. End Property
  1030.  
  1031. ' Let
  1032. Friend Property Let VertSizeInc(ByVal nIncrement As Long)
  1033.   FABS.szSizeInc.cy = nIncrement
  1034. End Property
  1035.  
  1036. ' Property Edge : Edge to dock on
  1037. ' Get : Retrieves the AppBar's edge.  If the AppBar is being positioned, its
  1038. ' proposed state is returned instead
  1039. Friend Property Get Edge() As TAppBarEdge
  1040.   If FabEdgeProposedPrev <> abeUnknown Then
  1041.     Edge = FabEdgeProposedPrev
  1042.   Else
  1043.     Edge = FABS.abEdge
  1044.   End If
  1045. End Property
  1046.  
  1047. ' Let : Changes the AppBar's edge to ABE_UNKNOWN, ABE_FLOAT or an ABE_edge
  1048. Friend Property Let Edge(ByVal abEdge As TAppBarEdge)
  1049.  
  1050.   Dim abCurrentEdge As TAppBarEdge
  1051.   Dim currentRect As Rect
  1052.   Dim rc As Rect
  1053.   Dim hwnd As Long
  1054.   
  1055.   ' If the AppBar is registered as auto-hide, unregister it
  1056.   abCurrentEdge = GetAutohideEdge()
  1057.  
  1058.   If abCurrentEdge <> abeUnknown Then
  1059.     ' Our AppBar is auto-hidden, unregister it
  1060.     AppBarMessage3 abmSetAutoHideBar, abCurrentEdge, False
  1061.   End If
  1062.   
  1063.   ' Save the new requested state
  1064.   FABS.abEdge = abEdge
  1065.  
  1066.   Select Case abEdge
  1067.  
  1068.     Case abeUnknown
  1069.       ' We are being completely unregistered.
  1070.       ' Probably, the AppBar window is being destroyed.
  1071.       ' If the AppBar is registered as NOT auto-hide, unregister it
  1072.       AppBarMessage1 abmRemove
  1073.  
  1074.     Case abeFloat
  1075.       ' We are floating and therefore are just a regular window.
  1076.       ' Tell the shell that the docked AppBar should be of 0x0 dimensions
  1077.       ' so that the workspace is not affected by the AppBar
  1078.       currentRect.Left = 0
  1079.       currentRect.Top = 0
  1080.       currentRect.Right = 0
  1081.       currentRect.Bottom = 0
  1082.       AppBarMessage4 abmSetPos, abEdge, False, currentRect
  1083.       With Self
  1084.         .Left = FABS.rcFloat.Left * Screen.TwipsPerPixelX
  1085.         .Top = FABS.rcFloat.Top * Screen.TwipsPerPixelY
  1086.         .Width = (FABS.rcFloat.Right - FABS.rcFloat.Left) * _
  1087.                  Screen.TwipsPerPixelX
  1088.         .Height = (FABS.rcFloat.Bottom - FABS.rcFloat.Top) * _
  1089.                   Screen.TwipsPerPixelY
  1090.       End With
  1091.  
  1092.     Case Else
  1093.       If AutoHide And (AppBarMessage3(abmSetAutoHideBar, Edge, True) = 0) Then
  1094.         ' We couldn't set the AppBar on a new edge, let's dock it instead
  1095.         FABS.bAutoHide = False
  1096.         ' Call a virtual function to let derived classes know that the AppBar
  1097.         ' changed from auto-hide to docked
  1098.         OnAppBarForcedToDocked
  1099.       End If
  1100.  
  1101.       GetRect Edge, rc
  1102.       If AutoHide Then
  1103.         currentRect.Left = 0
  1104.         currentRect.Top = 0
  1105.         currentRect.Right = 0
  1106.         currentRect.Bottom = 0
  1107.         AppBarMessage4 abmSetPos, abeLeft, False, currentRect
  1108.       Else
  1109.         ' Tell the shell where the AppBar is
  1110.         AppBarMessage4 abmSetPos, abEdge, False, rc
  1111.       End If
  1112.  
  1113.       AdjustLocationForAutohide FbAutoHideIsVisible, rc
  1114.  
  1115.       ' Slide window in from or out to the edge
  1116.       SlideWindow rc
  1117.  
  1118.   End Select
  1119.  
  1120.   ' Set the AppBar's z-order appropriately
  1121.   hwnd = HWND_NOTOPMOST ' Assume normal Z-Order
  1122.   If FABS.bAlwaysOnTop Then
  1123.     ' If we are supposed to be always-on-top, put us there
  1124.     hwnd = HWND_TOPMOST
  1125.     If FbFullScreenAppOpen Then
  1126.       ' But, if a full-screen window is opened, put ourself at the bottom
  1127.       ' of the z-order so that we don't cover the full-screen window
  1128.       hwnd = HWND_BOTTOM
  1129.     End If
  1130.   End If
  1131.   SetWindowPos Self.hwnd, _
  1132.                hwnd, _
  1133.                0, 0, 0, 0, _
  1134.                SWP_NOMOVE Or SWP_NOSIZE Or SWP_NOACTIVATE
  1135.  
  1136.   ' Make sure that any auto-hide appbars stay on top of us after we move
  1137.   ' even though our activation state has not changed
  1138.   AppBarMessage1 abmActivate
  1139.  
  1140.   ' Tell our derived class that there is a state change
  1141.   OnAppBarStateChange False, abEdge
  1142.  
  1143.   ' Show or hide the taskbar entry depending on AppBar position
  1144.   
  1145.   Select Case FABS.abTaskEntry
  1146.     Case abtShow
  1147.       ModifyStyle Self.hwnd, _
  1148.                   GWL_EXSTYLE, _
  1149.                   0, _
  1150.                   WS_EX_APPWINDOW, _
  1151.                   0, _
  1152.                   True
  1153.     Case abtHide
  1154.       ModifyStyle Self.hwnd, _
  1155.                   GWL_EXSTYLE, _
  1156.                   WS_EX_APPWINDOW, _
  1157.                   0, _
  1158.                   0, _
  1159.                   True
  1160.     Case abtFloatDependent
  1161.       Select Case abEdge
  1162.         Case abeFloat
  1163.           ModifyStyle Self.hwnd, _
  1164.                       GWL_EXSTYLE, _
  1165.                       0, _
  1166.                       WS_EX_APPWINDOW, _
  1167.                       0, _
  1168.                       True
  1169.         Case abeLeft, abeTop, abeRight, abeBottom
  1170.           ModifyStyle Self.hwnd, _
  1171.                       GWL_EXSTYLE, _
  1172.                       WS_EX_APPWINDOW, _
  1173.                       0, _
  1174.                       0, _
  1175.                       True
  1176.       End Select
  1177.   End Select
  1178.  
  1179. End Property
  1180.  
  1181. ' Property AutoHide : Auto-hide On/Off
  1182. ' Get : Returns TRUE if Auto-hide is on, FALSE if Auto-hide is off
  1183. Friend Property Get AutoHide() As Boolean
  1184.   AutoHide = FABS.bAutoHide
  1185. End Property
  1186.  
  1187. ' Let : Sets the Auto-hide behavior
  1188. Friend Property Let AutoHide(ByVal bAutoHide As Boolean)
  1189.   FABS.bAutoHide = bAutoHide
  1190. End Property
  1191.     
  1192. ' Property AlwaysOnTop : Always On Top On/Off
  1193. ' Get : Returns TRUE if AppBar is always on topAuto-hide, FALSE otherwise
  1194. Friend Property Get AlwaysOnTop() As Boolean
  1195.   AlwaysOnTop = FABS.bAlwaysOnTop
  1196. End Property
  1197.  
  1198. ' Let : Sets the AlwaysOnTop behavior
  1199. Friend Property Let AlwaysOnTop(ByVal bAlwaysOnTop As Boolean)
  1200.   FABS.bAlwaysOnTop = bAlwaysOnTop
  1201. End Property
  1202.  
  1203. ' Property SlideEffect : Slide Effect On/Off
  1204. ' Get
  1205. Friend Property Get SlideEffect() As Boolean
  1206.   SlideEffect = FABS.bSlideEffect
  1207. End Property
  1208.  
  1209. ' Let
  1210. Friend Property Let SlideEffect(ByVal bSlideEffect As Boolean)
  1211.   FABS.bSlideEffect = bSlideEffect
  1212. End Property
  1213.  
  1214. ' Property SlideTime
  1215. ' Get
  1216. Friend Property Get SlideTime() As Long
  1217.   SlideTime = FABS.nTimerInterval
  1218. End Property
  1219.  
  1220. ' Let
  1221. Friend Property Let SlideTime(ByVal nInterval As Long)
  1222.   ' Kill the current timer
  1223.   KillTimer Self.hwnd, AUTO_HIDE_TIMER_ID
  1224.   ' Set the new timer interval
  1225.   FABS.nTimerInterval = nInterval
  1226.   ' Recreate the timer
  1227.   SetTimer Self.hwnd, AUTO_HIDE_TIMER_ID, FABS.nTimerInterval, 0
  1228. End Property
  1229.  
  1230. ' Property HorzDockSize : Height when docked horizontally
  1231. ' Get
  1232. Friend Property Get HorzDockSize() As Long
  1233.   HorzDockSize = FABS.szDockSize.cy
  1234. End Property
  1235.  
  1236. ' Let
  1237. Friend Property Let HorzDockSize(ByRef lSize As Long)
  1238.   FABS.szDockSize.cy = lSize
  1239. End Property
  1240.  
  1241. ' Property VertDockSize : Width when docked vertically
  1242. ' Get
  1243. Friend Property Get VertDockSize() As Long
  1244.   VertDockSize = FABS.szDockSize.cx
  1245. End Property
  1246.  
  1247. ' Let
  1248. Friend Property Let VertDockSize(ByRef lSize As Long)
  1249.   FABS.szDockSize.cx = lSize
  1250. End Property
  1251.  
  1252. ' AppBar rectangle when floating
  1253.  
  1254. ' Property FloatLeft
  1255. ' Get
  1256. Friend Property Get FloatLeft() As Long
  1257.   FloatLeft = FABS.rcFloat.Left
  1258. End Property
  1259.  
  1260. ' Let
  1261. Friend Property Let FloatLeft(ByRef lPos As Long)
  1262.   FABS.rcFloat.Left = lPos
  1263. End Property
  1264.  
  1265. ' Property FloatTop
  1266. ' Get
  1267. Friend Property Get FloatTop() As Long
  1268.   FloatTop = FABS.rcFloat.Top
  1269. End Property
  1270.  
  1271. ' Let
  1272. Friend Property Let FloatTop(ByRef lPos As Long)
  1273.   FABS.rcFloat.Top = lPos
  1274. End Property
  1275.  
  1276. ' Property FloatRight
  1277. ' Get
  1278. Friend Property Get FloatRight() As Long
  1279.   FloatRight = FABS.rcFloat.Right
  1280. End Property
  1281.  
  1282. ' Let
  1283. Friend Property Let FloatRight(ByRef lPos As Long)
  1284.   FABS.rcFloat.Right = lPos
  1285. End Property
  1286.  
  1287. ' Property FloatBottom
  1288. ' Get
  1289. Friend Property Get FloatBottom() As Long
  1290.   FloatBottom = FABS.rcFloat.Bottom
  1291. End Property
  1292.  
  1293. ' Let
  1294. Friend Property Let FloatBottom(ByRef lPos As Long)
  1295.   FABS.rcFloat.Bottom = lPos
  1296. End Property
  1297.  
  1298. ' AppBar MinMax dimensions when floating
  1299.  
  1300. ' Property MinWidth
  1301. ' Get
  1302. Friend Property Get MinWidth() As Long
  1303.   MinWidth = FABS.nMinWidth
  1304. End Property
  1305.  
  1306. ' Let
  1307. Friend Property Let MinWidth(ByVal nWidth As Long)
  1308.   FABS.nMinWidth = nWidth
  1309. End Property
  1310.  
  1311. ' Property MinHeight
  1312. ' Get
  1313. Friend Property Get MinHeight() As Long
  1314.   MinHeight = FABS.nMinHeight
  1315. End Property
  1316.  
  1317. ' Let
  1318. Friend Property Let MinHeight(ByVal nHeight As Long)
  1319.   FABS.nMinHeight = nHeight
  1320. End Property
  1321.  
  1322. ' Property MaxWidth
  1323. ' Get
  1324. Friend Property Get MaxWidth() As Long
  1325.   MaxWidth = FABS.nMaxWidth
  1326. End Property
  1327.  
  1328. ' Let
  1329. Friend Property Let MaxWidth(ByVal nWidth As Long)
  1330.   FABS.nMaxWidth = nWidth
  1331. End Property
  1332.  
  1333. ' Property MinHeight
  1334. ' Get
  1335. Friend Property Get MaxHeight() As Long
  1336.   MaxHeight = FABS.nMaxHeight
  1337. End Property
  1338.  
  1339. ' Let
  1340. Friend Property Let MaxHeight(ByVal nHeight As Long)
  1341.   FABS.nMaxHeight = nHeight
  1342. End Property
  1343.  
  1344. ' Property MinHorzDockSize : Min Height when docked horizontally
  1345. ' Get
  1346. Friend Property Get MinHorzDockSize() As Long
  1347.   MinHorzDockSize = FABS.szMinDockSize.cy
  1348. End Property
  1349.  
  1350. ' Let
  1351. Friend Property Let MinHorzDockSize(ByVal lSize As Long)
  1352.   FABS.szMinDockSize.cy = lSize
  1353. End Property
  1354.  
  1355. ' Property MaxHorzDockSize : Max Height when docked horizontally
  1356. ' Get
  1357. Friend Property Get MaxHorzDockSize() As Long
  1358.   MaxHorzDockSize = FABS.szMaxDockSize.cy
  1359. End Property
  1360.  
  1361. ' Let
  1362. Friend Property Let MaxHorzDockSize(ByVal lSize As Long)
  1363.   FABS.szMaxDockSize.cy = lSize
  1364. End Property
  1365.  
  1366. ' Property MinVertDockSize : Min Width when docked vertically
  1367. ' Get
  1368. Friend Property Get MinVertDockSize() As Long
  1369.   MinVertDockSize = FABS.szMinDockSize.cx
  1370. End Property
  1371.  
  1372. ' Let
  1373. Friend Property Let MinVertDockSize(ByVal lSize As Long)
  1374.   FABS.szMinDockSize.cx = lSize
  1375. End Property
  1376.  
  1377. ' Property MaxVertDockSize : Max Width when docked vertically
  1378. ' Get
  1379. Friend Property Get MaxVertDockSize() As Long
  1380.   MaxVertDockSize = FABS.szMaxDockSize.cx
  1381. End Property
  1382.  
  1383. ' Let
  1384. Friend Property Let MaxVertDockSize(ByVal lSize As Long)
  1385.   FABS.szMaxDockSize.cx = lSize
  1386. End Property
  1387.  
  1388. ' Property TaskEntry : AppBar behavior in the Window Taskbar
  1389. ' Get
  1390. Friend Property Get TaskEntry() As TAppBarTaskEntry
  1391.   TaskEntry = FABS.abTaskEntry
  1392. End Property
  1393.  
  1394. ' Let
  1395. Friend Property Let TaskEntry(abTaskEntry As TAppBarTaskEntry)
  1396.   FABS.abTaskEntry = abTaskEntry
  1397. End Property
  1398.  
  1399. ' Property RootKey : where settings should be loaded/saved in the registry
  1400. ' Get
  1401. Friend Property Get RootKey() As Long
  1402.   RootKey = FabSettingsLocation.nRootKey
  1403. End Property
  1404.  
  1405. ' Let
  1406. Friend Property Let RootKey(lKey As Long)
  1407.   FabSettingsLocation.nRootKey = lKey
  1408. End Property
  1409.  
  1410. ' Property KeyName : where settings should be loaded/saved in the registry
  1411. ' Get
  1412. Friend Property Get KeyName() As String
  1413.   KeyName = FabSettingsLocation.KeyName
  1414. End Property
  1415.  
  1416. ' Let
  1417. Friend Property Let KeyName(strKey As String)
  1418.   FabSettingsLocation.KeyName = strKey
  1419. End Property
  1420.  
  1421. ' Overridable functions
  1422.  
  1423. ' Called when the AppBar's proposed state changes
  1424. Friend Function OnAppBarStateChange(ByVal bProposed As Boolean, _
  1425.                                     ByVal abEdgeProposed As TAppBarEdge)
  1426.  
  1427.   Dim bFullDragOn As Long
  1428.   
  1429.   ' Find out if the user has FullDrag turned on
  1430.   SystemParametersInfo SPI_GETDRAGFULLWINDOWS, 0, VarPtr(bFullDragOn), 0
  1431.  
  1432.   ' If FullDrag is turned on OR the appbar has changed position
  1433.   If bFullDragOn Or Not bProposed Then
  1434.     If abEdgeProposed = abeFloat Then
  1435.       ' Show the window adornments
  1436.       ModifyStyle Self.hwnd, _
  1437.                   GWL_STYLE, _
  1438.                   0, _
  1439.                   WS_CAPTION Or WS_SYSMENU, _
  1440.                   SWP_DRAWFRAME, _
  1441.                   False
  1442.     Else
  1443.       ' Hide the window adornments
  1444.       ModifyStyle Self.hwnd, _
  1445.                   GWL_STYLE, _
  1446.                   WS_CAPTION Or WS_SYSMENU, _
  1447.                   0, _
  1448.                   SWP_DRAWFRAME, _
  1449.                   False
  1450.     End If
  1451.   End If
  1452.  
  1453. End Function
  1454.  
  1455. ' Called if user attempts to dock an Autohide AppBar on
  1456. ' an edge that already contains an Autohide AppBar
  1457. Friend Function OnAppBarForcedToDocked()
  1458.   
  1459.   ' Display the application name as the message box caption text.
  1460.   MessageBox Self.hwnd, _
  1461.              "There is already an auto hidden window on this edge." + _
  1462.              Chr(10) + Chr(13) + _
  1463.              "Only one auto hidden window is allowed on each edge.", _
  1464.              Self.Caption, _
  1465.              MB_OK + MB_ICONINFORMATION
  1466.  
  1467. End Function
  1468.  
  1469. ' Called when AppBar gets an ABN_FULLSCREENAPP notification
  1470. Friend Function OnABNFullScreenApp(ByVal bOpen As Boolean)
  1471.  
  1472.   ' This function is called when a FullScreen window is openning or
  1473.   ' closing. A FullScreen window is a top-level window that has its caption
  1474.   ' above the top of the screen allowing the entire screen to be occupied
  1475.   ' by the window's client area.
  1476.  
  1477.   ' If the AppBar is a topmost window when a FullScreen window is activated,
  1478.   ' we need to change our window to a non-topmost window so that the AppBar
  1479.   ' doesn't cover the FullScreen window's client area.
  1480.  
  1481.   ' If the FullScreen window is closing, we need to set the AppBar's
  1482.   ' Z-Order back to when the user wants it to be.
  1483.   FbFullScreenAppOpen = bOpen
  1484.   UpdateBar
  1485.  
  1486. End Function
  1487.  
  1488. ' Called when AppBar gets an ABN_POSCHANGED notification
  1489. Friend Function OnABNPosChanged()
  1490.  
  1491.   ' The TaskBar or another AppBar has changed its size or position
  1492.   If (Edge <> abeFloat) And (Not AutoHide) Then
  1493.     ' If we're not floating and we're not auto-hidden, we have to
  1494.     ' reposition our window
  1495.     UpdateBar
  1496.   End If
  1497.  
  1498. End Function
  1499.  
  1500. ' Called when AppBar gets an ABN_WINDOWARRANGE notification
  1501. Friend Function OnABNWindowArrange(ByVal bBeginning As Boolean)
  1502.   
  1503.   ' This function intentionally left blank
  1504.  
  1505. End Function
  1506.  
  1507.  
  1508. ' Message handlers
  1509.  
  1510. ' Called when the AppBar receives a WM_APPBARNOTIFY window message
  1511. Friend Function OnAppBarCallbackMsg(ByVal wParam, ByVal lParam) As Long
  1512.  
  1513.   Select Case wParam
  1514.     Case ABN_FULLSCREENAPP
  1515.       OnABNFullScreenApp CBool(lParam)
  1516.     Case ABN_POSCHANGED
  1517.       OnABNPosChanged
  1518.     Case ABN_WINDOWARRANGE
  1519.       OnABNWindowArrange CBool(lParam)
  1520.   End Select
  1521.   
  1522.   OnAppBarCallbackMsg = 0
  1523.  
  1524. End Function
  1525.  
  1526. ' Called when the AppBar form is first created
  1527. Friend Function OnCreate()
  1528.  
  1529.   Dim hMenu As Long
  1530.   
  1531.   ' Associate a timer with the AppBar.  The timer is used to determine
  1532.   ' when a visible, inactive, auto-hide AppBar should be re-hidden
  1533.   SetTimer Self.hwnd, AUTO_HIDE_TIMER_ID, FABS.nTimerInterval, 0
  1534.  
  1535.   ' Save the initial size and position of the floating AppBar
  1536.   With FABS.rcFloat
  1537.     .Left = Self.Left \ Screen.TwipsPerPixelX
  1538.     .Top = Self.Top \ Screen.TwipsPerPixelY
  1539.     .Right = (Self.Left + Self.Width) \ Screen.TwipsPerPixelX
  1540.     .Bottom = (Self.Top + Self.Height) \ Screen.TwipsPerPixelY
  1541.   End With
  1542.  
  1543.   ' Register our AppBar window with the Shell
  1544.   AppBarMessage1 abmNew
  1545.  
  1546.   ' Update AppBar internal state
  1547.   UpdateBar
  1548.  
  1549.   ' Remove system menu
  1550.   hMenu = GetSystemMenu(Self.hwnd, False)
  1551.   DeleteMenu hMenu, SC_RESTORE, MF_BYCOMMAND
  1552.   DeleteMenu hMenu, SC_MINIMIZE, MF_BYCOMMAND
  1553.   DeleteMenu hMenu, SC_MAXIMIZE, MF_BYCOMMAND
  1554.  
  1555. End Function
  1556.  
  1557. ' Called when the AppBar form is about to be destroyed
  1558. Friend Function OnDestroy()
  1559.  
  1560.   ' Kill the Autohide timer
  1561.   KillTimer Self.hwnd, AUTO_HIDE_TIMER_ID
  1562.   
  1563.   ' Unregister our AppBar window with the Shell
  1564.   Edge = abeUnknown
  1565.  
  1566. End Function
  1567.  
  1568. ' Called when the AppBar receives a WM_WINDOWPOSCHANGED message
  1569. Friend Function OnWindowPosChanged()
  1570.   
  1571.   ' When our window changes position, tell the Shell so that any
  1572.   ' auto-hidden AppBar on our edge stays on top of our window making it
  1573.   ' always accessible to the user
  1574.   AppBarMessage1 abmWindowPosChanged
  1575.   
  1576. End Function
  1577.  
  1578. ' Called when the AppBar receives a WM_ACTIVATE message
  1579. Friend Function OnActivate(ByVal wParam As Long)
  1580.  
  1581.   If wParam = WA_INACTIVE Then
  1582.     ' Hide the AppBar if we are docked and auto-hidden
  1583.     ShowHiddenAppBar False
  1584.   End If
  1585.   
  1586.   ' When our window changes position, tell the Shell so that any
  1587.   ' auto-hidden AppBar on our edge stays on top of our window making it
  1588.   ' always accessible to the user.
  1589.   AppBarMessage1 abmActivate
  1590.  
  1591. End Function
  1592.  
  1593. ' Called every timer tick
  1594. Friend Function OnAppBarTimer()
  1595.  
  1596.   Dim pt As POINTS
  1597.   Dim rc As Rect
  1598.   
  1599.   If GetActiveWindow <> Self.hwnd Then
  1600.     ' Possibly hide the AppBar if we are not the active window
  1601.     ' Get the position of the mouse and the AppBar's position
  1602.     ' Everything must be in screen coordinates
  1603.     pt = GetMessagePosition
  1604.     GetWindowRect Self.hwnd, rc
  1605.     ' Add a little margin around the AppBar
  1606.     InflateRect rc, _
  1607.                 2 * GetSystemMetrics(SM_CXDOUBLECLK), _
  1608.                 2 * GetSystemMetrics(SM_CYDOUBLECLK)
  1609.     If Not PtInRect(rc, pt) Then
  1610.       ' If the mouse is NOT over the AppBar, hide the AppBar
  1611.       ShowHiddenAppBar False
  1612.     End If
  1613.   End If
  1614.  
  1615. End Function
  1616.  
  1617. ' Called when the AppBar receives a WM_NCMOUSEMOVE message
  1618. Friend Function OnNcMouseMove()
  1619.   
  1620.   ' If we are a docked, auto-hidden AppBar, shown us
  1621.   ' when the user moves over our non-client area
  1622.   ShowHiddenAppBar True
  1623.   
  1624. End Function
  1625.  
  1626. ' Called when the AppBar receives a WM_NCHITTEST message
  1627. Friend Function OnNcHitTest(ByVal lParam As Long, ByRef Result As Long) As Long
  1628.  
  1629.   Dim u As Long
  1630.   Dim bPrimaryMouseBtnDown As Boolean
  1631.   Dim rcClient As Rect
  1632.   Dim pt As POINTAPI
  1633.   Dim vKey As Long
  1634.   Dim XPos As Integer
  1635.   Dim YPos As Integer
  1636.   
  1637.   ' Find out what the system thinks is the hit test code
  1638.   u = Result
  1639.   
  1640.   ' Get cursor position in screen coordinates
  1641.   XPos = lParam And &H7FFF
  1642.   YPos = (lParam And &H7FFF0000) \ &H10000
  1643.  
  1644.   ' NOTE: If the user presses the secondary mouse button, pretend that the
  1645.   ' user clicked on the client area so that we get WM_CONTEXTMENU messages
  1646.   If GetSystemMetrics(SM_SWAPBUTTON) <> 0 Then
  1647.     vKey = VK_RBUTTON
  1648.   Else
  1649.     vKey = VK_LBUTTON
  1650.   End If
  1651.   bPrimaryMouseBtnDown = CBool(GetAsyncKeyState(vKey) And &H8000)
  1652.  
  1653.   pt.x = XPos
  1654.   pt.y = YPos
  1655.   ScreenToClient Self.hwnd, pt
  1656.   If (u = HTCLIENT) And bPrimaryMouseBtnDown _
  1657.      And Not ControlAtPos(pt, False) Then
  1658.     ' User clicked in client area, allow AppBar to move.  We get this
  1659.     ' behavior by pretending that the user clicked on the caption area
  1660.     u = HTCAPTION
  1661.   End If
  1662.  
  1663.   ' If the AppBar is floating and the hittest code is a resize code...
  1664.   If ((Edge = abeFloat) And _
  1665.       (HTSIZEFIRST <= u) And (u <= HTSIZELAST)) Then
  1666.     Select Case u
  1667.       Case HTLEFT, HTRIGHT
  1668.         If FABS.szSizeInc.cx = 0 Then
  1669.           u = HTBORDER
  1670.         End If
  1671.       Case HTTOP, HTBOTTOM
  1672.         If FABS.szSizeInc.cy = 0 Then
  1673.           u = HTBORDER
  1674.         End If
  1675.       Case HTTOPLEFT
  1676.         If (FABS.szSizeInc.cx = 0) And (FABS.szSizeInc.cy = 0) Then
  1677.           u = HTBORDER
  1678.         ElseIf (FABS.szSizeInc.cx = 0) And (FABS.szSizeInc.cy <> 0) Then
  1679.           u = HTTOP
  1680.         ElseIf (FABS.szSizeInc.cx <> 0) And (FABS.szSizeInc.cy = 0) Then
  1681.           u = HTLEFT
  1682.         End If
  1683.       Case HTTOPRIGHT
  1684.         If (FABS.szSizeInc.cx = 0) And (FABS.szSizeInc.cy = 0) Then
  1685.           u = HTBORDER
  1686.         ElseIf (FABS.szSizeInc.cx = 0) And (FABS.szSizeInc.cy <> 0) Then
  1687.           u = HTTOP
  1688.         ElseIf (FABS.szSizeInc.cx <> 0) And (FABS.szSizeInc.cy = 0) Then
  1689.           u = HTRIGHT
  1690.         End If
  1691.       Case HTBOTTOMLEFT
  1692.         If (FABS.szSizeInc.cx = 0) And (FABS.szSizeInc.cy = 0) Then
  1693.           u = HTBORDER
  1694.         ElseIf (FABS.szSizeInc.cx = 0) And (FABS.szSizeInc.cy <> 0) Then
  1695.           u = HTBOTTOM
  1696.         ElseIf (FABS.szSizeInc.cx <> 0) And (FABS.szSizeInc.cy = 0) Then
  1697.           u = HTLEFT
  1698.         End If
  1699.       Case HTBOTTOMRIGHT
  1700.         If (FABS.szSizeInc.cx = 0) And (FABS.szSizeInc.cy = 0) Then
  1701.           u = HTBORDER
  1702.         ElseIf (FABS.szSizeInc.cx = 0) And (FABS.szSizeInc.cy <> 0) Then
  1703.           u = HTBOTTOM
  1704.         ElseIf (FABS.szSizeInc.cx <> 0) And (FABS.szSizeInc.cy = 0) Then
  1705.           u = HTRIGHT
  1706.         End If
  1707.     End Select
  1708.   End If
  1709.  
  1710.   ' When the AppBar is docked, the user can resize only one edge.
  1711.   ' This next section determines which edge the user can resize.
  1712.   ' To allow resizing, the AppBar window must have the WS_THICKFRAME style
  1713.  
  1714.   ' If the AppBar is docked and the hittest code is a resize code...
  1715.   If ((Edge <> abeFloat) And (Edge <> abeUnknown) And _
  1716.       (HTSIZEFIRST <= u) And (u <= HTSIZELAST)) Then
  1717.  
  1718.     If (IsEdgeLeftOrRight(Edge) And (FABS.szSizeInc.cx = 0)) Or _
  1719.        (Not IsEdgeLeftOrRight(Edge) And (FABS.szSizeInc.cy = 0)) Then
  1720.       ' If the width/height size increment is zero, then resizing is NOT
  1721.       ' allowed for the edge that the AppBar is docked on
  1722.       u = HTBORDER ' Pretend that the mouse is not on a resize border
  1723.     Else
  1724.       ' Resizing IS allowed for the edge that the AppBar is docked on
  1725.       ' Get the location of the appbar's client area in screen coordinates
  1726.       GetClientRect Self.hwnd, rcClient
  1727.       pt.x = rcClient.Left
  1728.       pt.y = rcClient.Top
  1729.       ClientToScreen Self.hwnd, pt
  1730.       rcClient.Left = pt.x
  1731.       rcClient.Top = pt.y
  1732.       pt.x = rcClient.Right
  1733.       pt.y = rcClient.Bottom
  1734.       ClientToScreen Self.hwnd, pt
  1735.       rcClient.Right = pt.x
  1736.       rcClient.Bottom = pt.y
  1737.  
  1738.       u = HTBORDER ' Assume that we can't resize
  1739.       Select Case Edge
  1740.         Case abeLeft
  1741.           If XPos > rcClient.Right Then
  1742.             u = HTRIGHT
  1743.           End If
  1744.         Case abeTop
  1745.           If YPos > rcClient.Bottom Then
  1746.             u = HTBOTTOM
  1747.           End If
  1748.         Case abeRight
  1749.           If XPos < rcClient.Left Then
  1750.             u = HTLEFT
  1751.           End If
  1752.         Case abeBottom
  1753.           If YPos < rcClient.Top Then
  1754.             u = HTTOP
  1755.           End If
  1756.       End Select
  1757.     End If
  1758.   End If
  1759.  
  1760.   ' Return the hittest code
  1761.   Result = u
  1762.  
  1763. End Function
  1764.  
  1765. ' Called when the AppBar receives a WM_ENTERSIZEMOVE message
  1766. Friend Function OnEnterSizeMove() As Long
  1767.  
  1768.   ' The user started moving/resizing the AppBar, save its current state
  1769.   FabEdgeProposedPrev = Edge
  1770.   
  1771.   ' Trap default processing
  1772.   OnEnterSizeMove = 0
  1773.  
  1774. End Function
  1775.  
  1776. ' Called when the AppBar receives a WM_EXITSIZEMOVE message
  1777. Friend Function OnExitSizeMove() As Long
  1778.   
  1779.   Dim abEdgeProposedPrev As TAppBarEdge
  1780.   Dim rc As Rect
  1781.   Dim rcWorkArea As Rect
  1782.   Dim w As Long
  1783.   Dim h As Long
  1784.  
  1785.   ' The user stopped moving/resizing the AppBar, set the new state
  1786.   ' Save the new proposed state of the AppBar
  1787.   abEdgeProposedPrev = FabEdgeProposedPrev
  1788.  
  1789.   ' Set the proposed state back to unknown.  This causes GetState
  1790.   ' to return the current state rather than the proposed state
  1791.   FabEdgeProposedPrev = abeUnknown
  1792.  
  1793.   ' Get the location of the window in screen coordinates
  1794.   GetWindowRect Self.hwnd, rc
  1795.  
  1796.   ' If the AppBar's state has changed...
  1797.   If Edge = abEdgeProposedPrev Then
  1798.     Select Case Edge
  1799.       Case abeLeft, abeRight
  1800.         ' Save the new width of the docked AppBar
  1801.         FABS.szDockSize.cx = rc.Right - rc.Left
  1802.       Case abeTop, abeBottom
  1803.         ' Save the new height of the docked AppBar
  1804.         FABS.szDockSize.cy = rc.Bottom - rc.Top
  1805.     End Select
  1806.   End If
  1807.  
  1808.   ' Always save the new position of the floating AppBar
  1809.   If abEdgeProposedPrev = abeFloat Then
  1810.     ' If AppBar was floating and keeps floating...
  1811.     If Edge = abeFloat Then
  1812.       FABS.rcFloat = rc
  1813.     ' If AppBar was docked and is going to float...
  1814.     Else
  1815.       ' Propose width and height depending on the current window position
  1816.       w = rc.Right - rc.Left
  1817.       h = rc.Bottom - rc.Top
  1818.       ' Adjust width and height
  1819.       SystemParametersInfo SPI_GETWORKAREA, 0, VarPtr(rcWorkArea), 0
  1820.       If (w >= (rcWorkArea.Right - rcWorkArea.Left)) Or _
  1821.          (h >= (rcWorkArea.Bottom - rcWorkArea.Top)) Then
  1822.         w = FABS.rcFloat.Right - FABS.rcFloat.Left
  1823.         h = FABS.rcFloat.Bottom - FABS.rcFloat.Top
  1824.       End If
  1825.       ' Save new floating position
  1826.       FABS.rcFloat.Left = rc.Left
  1827.       FABS.rcFloat.Top = rc.Top
  1828.       FABS.rcFloat.Right = rc.Left + w
  1829.       FABS.rcFloat.Bottom = rc.Top + h
  1830.     End If
  1831.   End If
  1832.  
  1833.   ' After setting the dimensions, set the AppBar to the proposed state
  1834.   Edge = abEdgeProposedPrev
  1835.   
  1836.   ' Trap default processing
  1837.   OnExitSizeMove = 0
  1838.  
  1839. End Function
  1840.  
  1841. ' Called when the AppBar receives a WM_MOVING message
  1842. Friend Function OnMoving(ByVal lParam As Long) As Long
  1843.   
  1844.   Dim rc As Rect
  1845.   Dim pt As POINTS
  1846.   Dim abEdgeProposed As TAppBarEdge
  1847.   Dim w As Long
  1848.   Dim h As Long
  1849.   
  1850.   ' We control the moving of the AppBar.  For example, if the mouse moves
  1851.   ' close to an edge, we want to dock the AppBar
  1852.   ' The lParam contains the window's position proposed by the system
  1853.   CopyMemory VarPtr(rc), lParam, Len(rc)
  1854.  
  1855.   ' Get the location of the mouse cursor
  1856.   pt = GetMessagePosition
  1857.  
  1858.   ' Where should the AppBar be based on the mouse position?
  1859.   abEdgeProposed = CalcProposedState(pt)
  1860.  
  1861.   If (FabEdgeProposedPrev <> abeFloat) And (abEdgeProposed = abeFloat) Then
  1862.     ' While moving, the user took us from a docked/autohidden state to
  1863.     ' the float state.  We have to calculate a rectangle location so that
  1864.     ' the mouse cursor stays inside the window.
  1865.     rc = FABS.rcFloat
  1866.     w = rc.Right - rc.Left
  1867.     h = rc.Bottom - rc.Top
  1868.     With rc
  1869.       .Left = pt.x - w \ 2
  1870.       .Top = pt.y
  1871.       .Right = pt.x - w \ 2 + w
  1872.       .Bottom = pt.y + h
  1873.     End With
  1874.   End If
  1875.  
  1876.   ' Remember the most-recently proposed state
  1877.   FabEdgeProposedPrev = abEdgeProposed
  1878.  
  1879.   ' Tell the system where to move the window based on the proposed state
  1880.   GetRect abEdgeProposed, rc
  1881.  
  1882.   ' Tell our derived class that there is a proposed state change
  1883.   OnAppBarStateChange True, abEdgeProposed
  1884.     
  1885.   ' Tell the system the new rectangle
  1886.   CopyMemory lParam, VarPtr(rc), Len(rc)
  1887.   
  1888.   ' Trap default processing
  1889.   OnMoving = 0
  1890.  
  1891. End Function
  1892.  
  1893. ' Called when the AppBar receives a WM_SIZING message
  1894. Friend Function OnSizing(ByVal wParam As Long, ByVal lParam As Long)
  1895.   
  1896.   Dim rc As Rect
  1897.   Dim rcBorder As Rect
  1898.   Dim nWidthNew As Long
  1899.   Dim nHeightNew As Long
  1900.   
  1901.   ' We control the sizing of the AppBar.  For example, if the user re-sizes
  1902.   ' an edge, we want to change the size in discrete increments.
  1903.   ' The lParam contains the window's position proposed by the system
  1904.   CopyMemory VarPtr(rc), lParam, Len(rc)
  1905.  
  1906.   ' Get the minimum allowed size of the window depending on current edge.
  1907.   ' This is the width/height of the window that must always be present
  1908.   rcBorder.Left = 0
  1909.   rcBorder.Top = 0
  1910.   With FABS
  1911.     Select Case .abEdge
  1912.       Case abeFloat
  1913.         rcBorder.Right = .nMinWidth
  1914.         rcBorder.Bottom = .nMinHeight
  1915.       Case Else
  1916.         rcBorder.Right = .szMinDockSize.cx
  1917.         rcBorder.Bottom = .szMinDockSize.cy
  1918.     End Select
  1919.   End With
  1920.   
  1921.   ' We force the window to resize in discrete units set by the FABS.szSizeInc
  1922.   ' member.  From the new, proposed window dimensions passed to us, round
  1923.   ' the width/height to the nearest discrete unit
  1924.   If FABS.szSizeInc.cx <> 0 Then
  1925.     nWidthNew = (((rc.Right - rc.Left) - (rcBorder.Right - rcBorder.Left) _
  1926.                  + (FABS.szSizeInc.cx \ 2)) \ FABS.szSizeInc.cx) _
  1927.                  * FABS.szSizeInc.cx + (rcBorder.Right - rcBorder.Left)
  1928.   Else
  1929.     nWidthNew = rc.Right - rc.Left
  1930.   End If
  1931.  
  1932.   If FABS.szSizeInc.cy <> 0 Then
  1933.     nHeightNew = (((rc.Bottom - rc.Top) - (rcBorder.Bottom - rcBorder.Top) _
  1934.                   + (FABS.szSizeInc.cy \ 2)) \ FABS.szSizeInc.cy) _
  1935.                   * FABS.szSizeInc.cy + (rcBorder.Bottom - rcBorder.Top)
  1936.   Else
  1937.     nHeightNew = rc.Bottom - rc.Top
  1938.   End If
  1939.  
  1940.   ' Adjust the rectangle's dimensions
  1941.   Select Case wParam
  1942.     
  1943.     Case WMSZ_LEFT
  1944.       rc.Left = rc.Right - nWidthNew
  1945.  
  1946.     Case WMSZ_TOP
  1947.       rc.Top = rc.Bottom - nHeightNew
  1948.  
  1949.     Case WMSZ_RIGHT
  1950.       rc.Right = rc.Left + nWidthNew
  1951.  
  1952.     Case WMSZ_BOTTOM
  1953.       rc.Bottom = rc.Top + nHeightNew
  1954.  
  1955.     Case WMSZ_BOTTOMLEFT
  1956.       rc.Bottom = rc.Top + nHeightNew
  1957.       rc.Left = rc.Right - nWidthNew
  1958.  
  1959.     Case WMSZ_BOTTOMRIGHT
  1960.       rc.Bottom = rc.Top + nHeightNew
  1961.       rc.Right = rc.Left + nWidthNew
  1962.  
  1963.     Case WMSZ_TOPLEFT
  1964.       rc.Left = rc.Right - nWidthNew
  1965.       rc.Top = rc.Bottom - nHeightNew
  1966.  
  1967.     Case WMSZ_TOPRIGHT
  1968.       rc.Top = rc.Bottom - nHeightNew
  1969.       rc.Right = rc.Left + nWidthNew
  1970.   
  1971.   End Select
  1972.   
  1973.   ' Tell the system the new rectangle
  1974.   CopyMemory lParam, VarPtr(rc), Len(rc)
  1975.   
  1976.   ' Trap default processing
  1977.   OnSizing = 0
  1978.  
  1979. End Function
  1980.  
  1981. ' Called when the AppBar receives a WM_GETMINMAXINFO message
  1982. Friend Function OnGetMinMaxInfo(ByVal lpMinMaxInfo As Long) As Long
  1983.   
  1984.   Dim mmi As MINMAXINFO
  1985.   
  1986.   CopyMemory VarPtr(mmi), lpMinMaxInfo, Len(mmi)
  1987.  
  1988.   If Edge = abeFloat Then
  1989.     With mmi
  1990.       .ptMinTrackSize.x = FABS.nMinWidth
  1991.       .ptMinTrackSize.y = FABS.nMinHeight
  1992.       .ptMaxTrackSize.x = FABS.nMaxWidth
  1993.       .ptMaxTrackSize.y = FABS.nMaxHeight
  1994.     End With
  1995.   Else
  1996.     With mmi
  1997.       .ptMinTrackSize.x = FABS.szMinDockSize.cx
  1998.       .ptMinTrackSize.y = FABS.szMinDockSize.cy
  1999.       .ptMaxTrackSize.x = GetSystemMetrics(SM_CXSCREEN)
  2000.       .ptMaxTrackSize.y = GetSystemMetrics(SM_CYSCREEN)
  2001.       If Not IsEdgeTopOrBottom(Edge) Then
  2002.         .ptMaxTrackSize.x = FABS.szMaxDockSize.cx
  2003.       End If
  2004.       If Not IsEdgeLeftOrRight(Edge) Then
  2005.         .ptMaxTrackSize.y = FABS.szMaxDockSize.cy
  2006.       End If
  2007.     End With
  2008.   End If
  2009.  
  2010.   CopyMemory lpMinMaxInfo, VarPtr(mmi), Len(mmi)
  2011.   
  2012.   ' Trap default processing
  2013.   OnGetMinMaxInfo = 0
  2014.  
  2015. End Function
  2016.  
  2017.  
  2018. ' AppBar-specific helper functions
  2019.  
  2020. ' Returns TRUE if abEdge is ABE_LEFT or ABE_RIGHT, else FALSE is returned
  2021. Friend Function IsEdgeLeftOrRight(ByVal abEdge As TAppBarEdge) As Boolean
  2022.   
  2023.   If (abEdge = abeLeft) Or (abEdge = abeRight) Then
  2024.     IsEdgeLeftOrRight = True
  2025.   Else
  2026.     IsEdgeLeftOrRight = False
  2027.   End If
  2028.  
  2029. End Function
  2030.     
  2031. ' Returns TRUE if abEdge is ABE_TOP or ABE_BOTTOM, else FALSE is returned
  2032. Friend Function IsEdgeTopOrBottom(ByVal abEdge As TAppBarEdge) As Boolean
  2033.  
  2034.   If (abEdge = abeTop) Or (abEdge = abeBottom) Then
  2035.     IsEdgeTopOrBottom = True
  2036.   Else
  2037.     IsEdgeTopOrBottom = False
  2038.   End If
  2039.  
  2040. End Function
  2041.  
  2042. ' Returns TRUE if abEdge is ABE_FLOAT, else FALSE is returned
  2043. Friend Function IsFloating(ByVal abEdge As TAppBarEdge) As Boolean
  2044.  
  2045.   If abEdge = abeFloat Then
  2046.     IsFloating = True
  2047.   Else
  2048.     IsFloating = False
  2049.   End If
  2050.   
  2051. End Function
  2052.  
  2053. ' Returns TRUE if abFlags contain an at least allowed edge to dock on
  2054. Friend Function IsDockable(ByVal abFlags As TAppBarFlags) As Boolean
  2055.   
  2056.   IsDockable = abFlags And _
  2057.                (abfAllowLeft Or abfAllowTop Or abfAllowRight Or abfAllowBottom)
  2058.  
  2059. End Function
  2060.  
  2061. ' Returns TRUE if abFlags contain abfAllowLeft and abfAllowRight
  2062. Friend Function IsDockableVertically(ByVal abFlags As TAppBarFlags) As Boolean
  2063.  
  2064.   IsDockableVertically = abFlags And (abfAllowLeft Or abfAllowRight)
  2065.  
  2066. End Function
  2067.  
  2068. ' Returns TRUE if abFlags contain abfAllowTop and abfAllowBottom
  2069. Friend Function IsDockableHorizontally(ByVal abFlags As TAppBarFlags) _
  2070.                                        As Boolean
  2071.   
  2072.   IsDockableHorizontally = abFlags And (abfAllowTop Or abfAllowBottom)
  2073.  
  2074. End Function
  2075.  
  2076. ' Forces the shell to update its AppBar list and the workspace area
  2077. Friend Function ResetSystemKnowledge()
  2078.  
  2079. #If DEBUG_MODE Then
  2080.   Dim abd As APPBARDATA
  2081.   abd.cbSize = Len(abd)
  2082.   abd.hwnd = 0
  2083.   SHAppBarMessage ABM_REMOVE, abd
  2084. #Else
  2085.   ' nothing to do when not in debug mode
  2086. #End If
  2087.  
  2088. End Function
  2089.  
  2090. ' Returns a proposed edge or ABE_FLOAT based on ABF_* flags and a
  2091. ' point specified in screen coordinates
  2092. Friend Function GetEdgeFromPoint(ByVal abFlags As TAppBarFlags, _
  2093.                                  ByRef pt As POINTS) As TAppBarEdge
  2094.  
  2095.   Dim rc As Rect
  2096.   Dim cxScreen As Long
  2097.   Dim cyScreen As Long
  2098.   Dim ptCenter As POINTS
  2099.   Dim ptOffset As POINTS
  2100.   Dim bIsLeftOrRight As Boolean
  2101.   Dim abSubstEdge As TAppBarEdge
  2102.   
  2103.   ' Let's get floating out of the way first
  2104.   If CBool(abfAllowFloat And abFlags) Then
  2105.  
  2106.     ' Get the rectangle that bounds the size of the screen
  2107.     ' minus any docked (but not-autohidden) AppBars
  2108.     SystemParametersInfo SPI_GETWORKAREA, 0, VarPtr(rc), 0
  2109.  
  2110.     ' Leave a 1/2 width/height-of-a-scrollbar gutter around the workarea
  2111.     InflateRect rc, _
  2112.                 -GetSystemMetrics(SM_CXVSCROLL), _
  2113.                 -GetSystemMetrics(SM_CYHSCROLL)
  2114.  
  2115.     ' If the point is in the adjusted workarea OR no edges are allowed
  2116.     If PtInRect(rc, pt) Or Not IsDockable(abFlags) Then
  2117.       ' The AppBar should float
  2118.       GetEdgeFromPoint = abeFloat
  2119.       Exit Function
  2120.     End If
  2121.   
  2122.   End If
  2123.  
  2124.   ' If we get here, the AppBar should be docked; determine the proper edge
  2125.   ' Get the dimensions of the screen
  2126.   cxScreen = GetSystemMetrics(SM_CXSCREEN)
  2127.   cyScreen = GetSystemMetrics(SM_CYSCREEN)
  2128.  
  2129.   ' Find the center of the screen
  2130.   ptCenter.x = cxScreen \ 2
  2131.   ptCenter.y = cyScreen \ 2
  2132.  
  2133.   ' Find the distance from the point to the center
  2134.   ptOffset.x = pt.x - ptCenter.x
  2135.   ptOffset.y = pt.y - ptCenter.y
  2136.  
  2137.   ' Determine if the point is farther from the left/right or top/bottom
  2138.   bIsLeftOrRight = _
  2139.     CBool((Abs(ptOffset.y) * cxScreen) <= (Abs(ptOffset.x) * cyScreen))
  2140.  
  2141.   ' Propose an edge
  2142.   If bIsLeftOrRight Then
  2143.     If 0 <= ptOffset.x Then
  2144.       GetEdgeFromPoint = abeRight
  2145.     Else
  2146.       GetEdgeFromPoint = abeLeft
  2147.     End If
  2148.   Else
  2149.     If 0 <= ptOffset.y Then
  2150.       GetEdgeFromPoint = abeBottom
  2151.     Else
  2152.       GetEdgeFromPoint = abeTop
  2153.     End If
  2154.   End If
  2155.  
  2156.   ' Calculate an edge substitute
  2157.   If CBool(abfAllowFloat And abFlags) Then
  2158.     abSubstEdge = abeFloat
  2159.   Else
  2160.     abSubstEdge = FABS.abEdge
  2161.   End If
  2162.  
  2163.   ' Check if the proposed edge is allowed. If not, return the edge substitute
  2164.   Select Case GetEdgeFromPoint
  2165.     Case abeLeft
  2166.       If Not CBool(abfAllowLeft And abFlags) Then
  2167.         GetEdgeFromPoint = abSubstEdge
  2168.       End If
  2169.     Case abeTop
  2170.       If Not CBool(abfAllowTop And abFlags) Then
  2171.         GetEdgeFromPoint = abSubstEdge
  2172.       End If
  2173.     Case abeRight
  2174.       If Not CBool(abfAllowRight And abFlags) Then
  2175.         GetEdgeFromPoint = abSubstEdge
  2176.       End If
  2177.     Case abeBottom
  2178.       If Not CBool(abfAllowBottom And abFlags) Then
  2179.         GetEdgeFromPoint = abSubstEdge
  2180.       End If
  2181.   End Select
  2182.  
  2183. End Function
  2184.  
  2185.  
  2186. ' PUBLIC
  2187.  
  2188.  
  2189. ' Public member functions
  2190.  
  2191. ' Extends the calling form with the AppBar properties and methods
  2192. Public Function Extends(ByVal Value As Form)
  2193.   
  2194.   Set Self = Value
  2195.   LinkCallback Value, Me
  2196.   OnCreate
  2197.  
  2198. End Function
  2199.  
  2200. ' Detaches the AppBar behavior from the calling form
  2201. Public Function Detach()
  2202.  
  2203.   OnDestroy
  2204.   DetachCallback
  2205.  
  2206. End Function
  2207.  
  2208. ' Forces the AppBar's visual appearance to match its internal state
  2209. Public Function UpdateBar()
  2210.   
  2211.   Edge = Edge
  2212.  
  2213. End Function
  2214.  
  2215. ' Loads settings from the registry at RootKey and KeyName location.
  2216. ' Returns TRUE if the settings are available, else FALSE
  2217. Public Function LoadSettings() As Boolean
  2218.   
  2219.   Dim hkSettings As Long
  2220.   Dim dwType As Long
  2221.   Dim dwSize As Long
  2222.   Dim abSettings As TAppBarSettings
  2223.   
  2224.   ' Set the default return value
  2225.   LoadSettings = False
  2226.   
  2227.   ' Open the key where settings are stored
  2228.   If RegOpenKeyEx(FabSettingsLocation.nRootKey, _
  2229.                   FabSettingsLocation.KeyName, _
  2230.                   0, _
  2231.                   KEY_ALL_ACCESS, _
  2232.                   hkSettings) = 0 Then
  2233.     
  2234.     ' Query the settings
  2235.     dwType = REG_BINARY
  2236.     dwSize = Len(abSettings)
  2237.     If RegQueryValueEx(hkSettings, "", 0, dwType, abSettings, dwSize) = 0 Then
  2238.       
  2239.       ' If the settings have been read, copy them in the FABS record
  2240.       If dwSize = Len(abSettings) Then
  2241.         FABS = abSettings
  2242.         LoadSettings = True
  2243.       End If
  2244.     
  2245.     End If
  2246.   
  2247.   End If
  2248.   
  2249.   ' Close the key
  2250.   RegCloseKey hkSettings
  2251.   
  2252. End Function
  2253.  
  2254. ' Saves settings into the registry at RootKey and KeyName location.
  2255. ' Returns TRUE if succeeded, else FALSE
  2256. Public Function SaveSettings() As Boolean
  2257.   
  2258.   Dim hkSettings As Long
  2259.   Dim dwDisposition As Long
  2260.   
  2261.   ' Set the default return value
  2262.   SaveSettings = False
  2263.   
  2264.   ' Create or open the key where settings must be stored
  2265.   If RegCreateKeyEx(FabSettingsLocation.nRootKey, _
  2266.                     FabSettingsLocation.KeyName, _
  2267.                     0, _
  2268.                     "", _
  2269.                     REG_OPTION_NON_VOLATILE, _
  2270.                     KEY_ALL_ACCESS, _
  2271.                     0, _
  2272.                     hkSettings, _
  2273.                     dwDisposition) = 0 Then
  2274.   
  2275.     ' Store the settings
  2276.     If RegSetValueEx(hkSettings, "", 0, REG_BINARY, FABS, Len(FABS)) = 0 Then
  2277.       
  2278.       ' Return success
  2279.       SaveSettings = True
  2280.     
  2281.     End If
  2282.   
  2283.   End If
  2284.   
  2285.   ' Close the key
  2286.   RegCloseKey hkSettings
  2287.   
  2288. End Function
  2289.